/*
 * 3Versao2.c
 *
 *  Created on: Sep 21, 2011
 *      Author: filipi
 */


#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <sys/time.h>
#include <sys/ipc.h>
#include <sys/msg.h>


#define MSGSZ (sizeof(int)+1)*10

typedef struct msgbuf {
	long    mtype;
	int    valor;
} message_buf;


//variaveis globais
//troca de mensagens
int status,msqid2,j;
key_t keyPF,keyFP;
message_buf sbuf,rbuf;
size_t buf_length;
keyPF = 1234;
keyFP = 4321;


typedef struct _COORDENADAS{
	int linha;
	int coluna;
}Coordenadas;

int indice(int l,int c,int k){
	return l*k+c;
}

Coordenadas coordenada(int indice,int k){
	Coordenadas coord;
	coord.linha=indice / k ;
	coord.coluna=indice % k;
	return coord;
}

void imprimeMatriz(int m,int k,int *matriz){
	int i,j;

	//printf("\n");
	for(i=0;i<m;i++){
			for(j=0;j<k;j++){
				if ((*(matriz+indice(i,j,k))>=0)&&*(matriz+indice(i,j,k))<100){
					//printf(" ");
				}
				if ((*(matriz+indice(i,j,k))>-10)&&*(matriz+indice(i,j,k))<10){
									//printf(" ");
				}
				if ((*(matriz+indice(i,j,k))>-100)&&*(matriz+indice(i,j,k))<=100){
					//printf(" ");
				}
				//printf("%d ",*(matriz+indice(i,j,k)));
			}
			//printf("\n");
		}
}

void preencheMatriz(int m,int k,int *matriz){
	int i;
	for(i=0;i<m*k;i++){
			*(matriz+i)= rand()%101;
			if (rand()%2==0){
				*(matriz+i)*=-1;
			}
		}
}

int encontraMax(int m,int k,int *matriz){
	int i,maximo;
	maximo = *matriz;
	for(i=0;i<m*k-1;i++){
		maximo = *(matriz+i)>maximo?*(matriz+i):maximo;
	}
	return maximo;
}

int encontraMin(int m,int k,int *matriz){
	int i,minimo;
	minimo = *(matriz+1);
		for(i=0;i<m*k;i++){
			minimo = *(matriz+i)<minimo?*(matriz+i):minimo;
		}
		return minimo;
}

void encontraNumero(int numero,int *matriz,int m,int k,Coordenadas *coorVector){

	int j=0,i=0;

	for(i=0;i<m*k;i++){
		if(matriz[i]==numero){
			coorVector[j]=coordenada(i,k);
			j++;
		}
	}

	coorVector[j].coluna=-1;
	coorVector[j].linha=-1;

}

void imprimeCoordenadas(Coordenadas *vec){
	Coordenadas coord;
	int j=0;
	while(1){
	coord = vec[j];
	if (coord.linha ==-1) break;
	//printf("Linha : %d Coluna %d\n",vec[j].linha,vec[j].coluna);
	j++;
	}

}


//calcular os produtos internos
void calculaProdutosInternos(int m, int k, int *matriz, int *produtoInterno){
	int i;
	int j;
	int pid;
	int msqid;
	
	
	
	
//	/*
	if ((msqid = msgget(keyPF, IPC_CREAT | 0666 )) < 0)
			{
					//printf("Erro ao abrir a fila");
			}
//*/
	
	
	

	for (i=0; i< m; i++){
		pid = fork();

		
		//printf("\n----PID = %d\n", pid);
		
		
		
		
		
		if (pid == 0){//filho criado

			produtoInterno[i] = 0;
			for (j=0; j< k; j++){
				produtoInterno[i] += ( *(matriz+indice(i,j,k)) * (*(matriz+indice(j,i,k))));
			}

			//printf("\nprodutoInterno: %d\n", produtoInterno[i]);

		
			//if ((msqid = msgget(keyPF+i, IPC_CREAT | 0666 )) < 0)
			//{
			//		//printf("Erro ao abrir a fila");
			//}
			
	

// /*
			sbuf.valor = produtoInterno[i];
			sbuf.mtype = 1;
			buf_length = sizeof(int) + 1 ;

			if (msgsnd(msqid, &sbuf, MSGSZ, IPC_NOWAIT) < 0) {
				//printf("Erro ao enviar mensagem...s");
			}
			else{
				//printf("Enviei mensagem");
			}
//*/
			//printf("\nCalculei prod interno: %d", produtoInterno[i]);





			exit(0);
		}

		else{
			
			
			
				//for (i= 0; i<m; i++){


					
				if (msgrcv(msqid, &rbuf, MSGSZ, 1, 0) < 0) {
					//printf("Erro nao foi possivel receber");
				}
				else{
				}

				produtoInterno[i] = rbuf.valor;
// */
				//printf("\nPRODUTOINTERNO RECEBIDO: %d\n", produtoInterno[i]);

				//sleep(1);
				
				wait(NULL);
			//}
		}
	}
}


//calcula desvio padrao
double desvioPadraoProdutos(int m, int *produtoInterno){

	int i;
	double acumulador = 0;
	for (i=0; i<m; i++){
		acumulador += produtoInterno[i];
	}
	acumulador = (acumulador / m); //aqui o acumulador tem a media dos valores do prod. interno

	i = 0;
	double acumulador2 = 0;
	for (i=0; i<m; i++){
		acumulador2 += pow((produtoInterno[i] - acumulador),2); //desvios medios ao quadrado
	}
	acumulador2 = (acumulador2 / m); //aqui acumulador2 tem a variancia

	//testando
	//printf("\n----acumulador: %f\n", acumulador);
	//printf("\n----produtoInterno[3]: %d\n", produtoInterno[3]);
	//printf("\n----acumulador2: %f\n", acumulador2);

	//acumulador2 = pow(acumulador2, 1/2); //aqui acumulador2 tem o desvio padrao
	//acumulador2 = sqrt(acumulador2);

	//testando
	//printf("\n----acumulador2: %f\n", acumulador2);

	return acumulador2;
}


int main(int argc,char **argv){
	struct timeval alfa, omega;

	srand(time(NULL));
	int m,k,*matriz,*produtoInterno;







	//printf("Versao 2\nEntre com o numero de linhas e colunas respectivamente.\n");

	scanf("%d %d",&m,&k);

	//printf("inicializando uma matriz com %d colunas e %d linhas",k,m);

	matriz=(int*)malloc(sizeof(int)*m*k);

	//falta verificar quantos produtos internos eu terei
	produtoInterno=(int*)malloc(sizeof(int)*m);

	preencheMatriz(m,k,matriz);
//	imprimeMatriz(m,k,matriz);
	int max = encontraMax(m,k,matriz);
	int min = encontraMin(m,k,matriz);
	//printf("\nValor máximo:%d , Valor mínimo:%d \n",max,min);

	Coordenadas coorMaxs[m*k+1];
	encontraNumero(max,matriz,m,k,coorMaxs);
	Coordenadas coorMins[m*k+1];
	encontraNumero(min,matriz,m,k,coorMins);

	//printf("\nCoordenadas dos menores valores\n\n");
	imprimeCoordenadas(coorMins);
	//printf("\nCoordenadas dos maiores valores\n\n");
	imprimeCoordenadas(coorMaxs);

	gettimeofday(&alfa, NULL);

	//calcula produto interno
	calculaProdutosInternos(m,k,matriz,produtoInterno);
	imprimeMatriz(m,1,produtoInterno);

	//!!!!!!!!!!!!! NAO ESTA DETECTANDO CORRETAMENTE !!!!!!!!!!!!! --acho que esta desconsiderando o ultimo prod. interno -- talvez o erro se estenda a outros lugares
	//encontra maior produto interno
	int maxProdutoInterno = encontraMax(m,1,produtoInterno);
	//printf("\nMaior produto interno: %d\n", maxProdutoInterno);

	//!!!!!!!!!!!!! NAO ESTA DETECTANDO CORRETAMENTE !!!!!!!!!!!!! --acho que esta desconsiderando o ultimo prod. interno
	//encontra menor produto interno
	int minProdutoInterno = encontraMin(m,1,produtoInterno);
	//printf("\nMenor produto interno: %d\n", minProdutoInterno);


	//coordenadas dos maiores e menores produtos internos
	Coordenadas coorMaxsProdutosInternos[m+1];
	encontraNumero(maxProdutoInterno, produtoInterno,m,1,coorMaxsProdutosInternos);
	Coordenadas coorMinsProdutosInternos[m+1];
	encontraNumero(minProdutoInterno, produtoInterno,m,1,coorMinsProdutosInternos);

	//imprime as coordenadas do maior produto interno
	//printf("\nCoordenadas do maior produto interno:\n\n");
	imprimeCoordenadas(coorMaxsProdutosInternos);
	//imprime as coordenadas do menor produto interno
	//printf("\nCoordenadas do menor produto interno:\n\n");
	imprimeCoordenadas(coorMinsProdutosInternos);


	//imprime desvio padrao dos produtos internos
	double desvioPadraoProdutosInternos = desvioPadraoProdutos(m, produtoInterno);
	//printf("\nDesvio padrao dos produtos internos: %f\n", desvioPadraoProdutosInternos);

	gettimeofday(&omega, NULL);
	int seconds  = omega.tv_sec  - alfa.tv_sec;
	float useconds = (omega.tv_usec - alfa.tv_usec)/1000000.0;
	printf("\nTempo de execucao em segundos: %f\n", seconds+useconds);

	return 0;
}

